Vue.js 면접 준비
작성일 : 2024.11.13
기본 개념:
1. Vue.js란 무엇이며 장점은?
- 프로그레시브 JavaScript 프레임워크
- 가상 DOM 사용으로 성능 최적화
- 반응형 데이터 바인딩
- 컴포넌트 기반 아키텍처
1-1) 프로그레시브 프레임워크란?
- 점진적으로 채택 가능한 구조
- 필요한 기능만 선택적으로 적용 가능
- 작은 프로젝트부터 대규모 애플리케이션까지 확장 가능
1-2) 가상 DOM의 이점:
- 실제 DOM 조작을 최소화하여 성능 향상
- 변경사항을 일괄 처리하여 렌더링 최적화
- 불필요한 업데이트 방지
1-3) 반응형 데이터 바인딩:
- 데이터 변경 시 자동으로 화면 갱신
- 양방향 바인딩으로 데이터와 UI 동기화
- Proxy 기반 반응형 시스템 (Vue 3)
1-4) 컴포넌트 기반 장점:
- 재사용 가능한 독립적 단위로 개발
- 유지보수성 향상
- 테스트가 용이
- 복잡한 UI를 작은 단위로 분리하여 관리
1-5) 추가적인 장점:
- 낮은 학습 곡선
- 풍부한 생태계와 도구 지원
- 가벼운 크기로 빠른 로딩
- React나 Angular에 비해 설정이 간단
2. Vue 인스턴스 라이프사이클 단계는?
beforeCreate -> created -> beforeMount -> mounted -> beforeUpdate -> updated -> beforeDestroy -> destroyed
2-1) beforeCreate
- 데이터와 이벤트가 설정되기 전 단계
- data, methods 접근 불가
- 사용 : 앱 초기화, 외부 라이브러리 설정
2-2) created
- 반응형 데이터와 이벤트 활성화
- DOM 접근 불가
- 사용 : API 호출, 데이터 초기화
2-3) beforeMount
- 템플릿 컴파일 완료, DOM 생성 직전
- 가상 DOM 존재하나 실제 DOM 없음
- 사용 : DOM 조작 전 준비 작업
2-4) mounted
- 실제 DOM 생성 완료
- $el 접근 가능
- 사용 : DOM 조작, 차트 라이브러리 초기화
2-5) beforeUpdate
- 데이터 변경 감지, DOM 업데이트 전
- 변경될 데이터 확인 가능
- 사용 : DOM 업데이트 전 데이터 가공
2-6) updated
- DOM 업데이트 완료
- 변경된 데이터와 DOM 동기화 상태
- 사용 : 외부 라이브러리와 동기화
2-7) beforeDestroy (Vue3: beforeUnmount)
- 인스턴스 제거 직전
- 인스턴스 기능 모두 동작
- 사용 : 이벤트 리스너 제거, 타이머 정리
2-8) destroyed (Vue3: unmounted)
- 모든 디렉티브, 이벤트 리스너 제거
- 하위 인스턴스도 모두 제거
- 사용 : 최종 정리 작업
3. Vue의 디렉티브란?
- v-if vs v-show 차이
- v-bind, v-model, v-on 사용법
- 커스텀 디렉티브 생성 방법
3-1) v-if vs v-show
- v-if: 조건부 렌더링, 조건 false시 DOM에서 완전 제거
- v-show: display CSS 속성 전환, DOM은 유지
<div v-if="isVisible">조건 충족시만 존재</div>
<div v-show="isVisible">항상 존재, 보임/숨김만 전환</div>
3-2) 주요 디렉티브 사용법
- v-bind: 속성 바인딩 (:로 축약)
<img v-bind:src="imageUrl">
<img :src="imageUrl"> // 축약형
- v-model: 양방향 데이터 바인딩
<input v-model="message">
<textarea v-model="content">
- v-on: 이벤트 리스너 (@로 축약)
<button v-on:click="handleClick">
<button @click="handleClick"> // 축약형
3-3) 커스텀 디렉티브 생성
Vue.directive('focus', {
mounted(el) {
el.focus()
}
})
// 컴포넌트에서 로컬 등록
directives: {
focus: {
mounted(el) {
el.focus()
}
}
}
사용:
<input v-focus>
3-4) 훅 함수들:
- mounted: 요소 추가될 때
- updated: 요소 업데이트될 때
- unmounted: 요소 제거될 때
데이터 관리:
4. Computed vs Methods vs Watch
- computed: 캐싱된 값, 의존성 있는 데이터
- methods: 호출할 때마다 실행
- watch: 데이터 변경 감지 및 사이드 이펙트 처리
4-1) Computed
computed: {
fullName() {
return this.firstName + ' ' + this.lastName
}
}
- 종속된 데이터가 변경될 때만 재계산
- 결과를 캐싱하여 성능 최적화
- getter/setter 지원
- 템플릿 내 복잡한 연산에 적합
4-2) Methods
methods: {
calculateTotal() {
return this.items.reduce((sum, item) => sum + item.price, 0)
}
}
- 호출될 때마다 실행
- 캐싱되지 않음
- 이벤트 핸들링에 적합
- 동적 인자 전달 가능
4-3) Watch
watch: {
searchQuery(newVal, oldVal) {
this.debounceSearch(newVal)
}
}
- 특정 데이터 변화 감지
- 비동기 처리, API 호출에 적합
- deep 옵션으로 깊은 감시 가능
- 이전값과 현재값 비교 가능
5. Vuex 관련
- 상태 관리의 필요성
- state, mutations, actions, getters 역할
- 모듈화 방법
5-1) 상태 관리의 필요성
- 상태 관리의 필요성
- state, mutations, actions, getters 역할
- 모듈화 방법
5-2) State, Mutations, Actions, Getters 역할
5-2-1) State
// Vuex
state: {
user: null,
isLoggedIn: false
}
// Pinia
state: () => ({
user: null,
isLoggedIn: false
})
- 중앙 집중식 상태 저장소
- 컴포넌트 간 공유되는 데이터
- 반응형 데이터 관리
5-2-2) Mutations (Vuex만 해당)
mutations: {
SET_USER(state, user) {
state.user = user
},
SET_LOGIN_STATUS(state, status) {
state.isLoggedIn = status
}
}
- 동기적 상태 변경
- state 직접 수정 가능한 유일한 방법
- 디버깅 추적 가능
Pinia에서 mutations가 제거된 이유:
1. 단순화
- 상태 관리 보일러플레이트 코드 감소
- actions에서 직접 상태 변경 가능
2. 개발 경험 향상
// Vuex - 복잡한 구조
actions: {
updateUser({ commit }, user) {
commit('SET_USER', user)
}
}
// Pinia - 단순한 구조
actions: {
updateUser(user) {
this.user = user
}
}
3. TypeScript 지원 강화
- mutation 없이도 타입 안정성 보장
- 직접 상태 수정으로 타입 추론 개선
4. DevTools 지원
- mutation 없이도 상태 변화 추적 가능
- 디버깅 용이성 유지
5-2-3) Actions
// Vuex
actions: {
async login({ commit }, credentials) {
const user = await api.login(credentials)
commit('SET_USER', user)
commit('SET_LOGIN_STATUS', true)
}
}
// Pinia
actions: {
async login(credentials) {
const user = await api.login(credentials)
this.user = user
this.isLoggedIn = true
}
}
- 비동기 작업 처리
- API 호출, 복잡한 로직 처리
- 여러 mutations/상태 변경 가 능
- 능동적 실행, 상태 변경
5-2-4) Getters
// Vuex & Pinia
getters: {
isAdmin: (state) => state.user?.role === 'admin',
fullName: (state) => `${state.user?.firstName} ${state.user?.lastName}`,
userProfile: (state) => (id) => state.users.find(u => u.id === id)
}
- 상태 기반 계산된 속성
- 캐싱되어 성능 최적화
- 다른 getter 재사용 가능
- 컴포넌트 로직 분리
- 반응형 계산, 상태 감시